#include "sslframe.h"
#include "ui_sslframe.h"

#include "testfunctions.h"
#include "sslclient.h"
#include "cryptotool.h"

SSLFrame* g_ssl_frame = nullptr;

typedef  void(*closure)();

void printInfo(const char* format, ...) {
    QString msg;
    va_list args;
    va_start(args, format);
    msg.vsprintf(format, args);
    va_end(args);
    printFormatedMessage(msg);
}

void printError(const char* format, ...) {
    QString msg;
    va_list args;
    va_start(args, format);
    msg.vsprintf(format, args);
    va_end(args);
    printFormatedMessage(msg, MSG_TYPE::ERROR);
}

void printFormatedMessage(const QString& msg, MSG_TYPE type) {
  QString color;
  switch(type) {
    case MSG_TYPE::ERROR:
    color = "red";
      break;
  default:
    color = "black";
      break;
  }
  QString print_msg = QString("<font color=\"%1\">%2</font>")
          .arg(color)
          .arg(msg);
  g_ssl_frame->printMsg(print_msg);
}

void TestSSL() {
    SSLClient client;
    client.Connect();
}


SSLFrame::SSLFrame(QWidget* parent)
    : QFrame(parent)
    , ui(new Ui::SSLFrame)
{
    ui->setupUi(this);
    g_ssl_frame = this;
    Init();
}

SSLFrame::~SSLFrame() {
    if(ui)
        delete ui;
}

void SSLFrame::Init() {
    ssl_client_ = new SSLClient(this);

    ui->comboBoxType->insertItem((int)TestCrypto, "test crypto");
    ui->comboBoxType->insertItem((int)TestDigest, "test digest");
    ui->comboBoxType->insertItem((int)TestSymmetric, "test symmetric");
    ui->comboBoxType->insertItem((int)TestAsymmetric, "test asymmetric");
    ui->comboBoxType->insertItem((int)TestSSL, "test ssl");
    ui->comboBoxType->insertItem((int)TestPKI, "test pki");

    InitTestFunctions();
}

void SSLFrame::OnTypeComboboxChanged(int index) {
  current_type_ = (TestType)index;
  InitFunctor(current_type_);
}

void SSLFrame::RunCryptoTool() {

  CryptoTool::CryptoType type;
  if(ui->toolSM2EncryptRatio->isChecked()) {
    type = CryptoTool::CryptoSM2Encrypt;
  } else if(ui->toolSM2DecryptRatio->isChecked()) {
    type = CryptoTool::CryptoSM2Decrypt;
  } else if(ui->toolSM2VerifyRatio->isChecked()) {
    type = CryptoTool::CryptoSM2Verify;
  } else if(ui->toolSM2SignRatio->isChecked()) {
    type = CryptoTool::CryptoSM2Sign;
  } else if(ui->toolSM2ZRatio->isChecked()) {
    type = CryptoTool::CryptoSM2ZEncrypt;
  } else if(ui->toolSM3DigestRatio->isChecked()) {
    type = CryptoTool::CryptoSM3Digest;
  } else if(ui->toolSM3HMACRatio->isChecked()) {
    type = CryptoTool::CryptoSM3HMac;
  }


}

void SSLFrame::InitTestFunctions() {
  connect(ui->comboBoxType, SIGNAL(currentIndexChanged(int )),
          this, SLOT(OnTypeComboboxChanged(int)));


  connect(ui->runButton, &QAbstractButton::clicked, [this]() {
    RunFunctor(current_type_);
  });

  ui->comboBoxFunctor->setCurrentIndex(0);
  InitFunctor(TestCrypto);

  current_type_ = TestPKI;
  ui->comboBoxType->setCurrentIndex(TestPKI);
  ui->comboBoxFunctor->setCurrentIndex(1);

  // connect(ui->clientTestButton,
  //         &QAbstractButton::clicked,
  //         ssl_client_,
  //         &SSLClient::TestConnect);
}

void SSLFrame::InitCryptoTool()
{
    crypto_tool_ = std::make_unique<CryptoTool>();
    connect(ui->toolSubmitBtn,
            &QAbstractButton::clicked,
            this,
            &SSLFrame::RunCryptoTool
    );


}

void SSLFrame::InitFunctor(TestType type)
{
  ui->comboBoxFunctor->disconnect();
  ui->comboBoxFunctor->clear();
  switch(type) {
    case TestCrypto:
      ui->comboBoxFunctor->addItem("TestHash", (long long)&TestHash);
      ui->comboBoxFunctor->addItem("TestBigNumber", (long long)&TestBigNumber);
    break;
  case TestDigest:
    ui->comboBoxFunctor->addItem("TestSM3", (long long)&TestSM3);
    ui->comboBoxFunctor->addItem("TestSha256", (long long)&TestSha256);
  break;
  case TestSymmetric:
    ui->comboBoxFunctor->addItem("TestSM4", (long long)&TestSM4);
    ui->comboBoxFunctor->addItem("TestAES128", (long long)&TestAES128);
  break;

  case TestAsymmetric:
    ui->comboBoxFunctor->addItem("TestSM2", (long long)&TestSM2);
    ui->comboBoxFunctor->addItem("TestRSA", (long long)&TestRSA);
    ui->comboBoxFunctor->addItem("TestDSA", (long long)&TestDSA);
    ui->comboBoxFunctor->addItem("TestECC", (long long)&TestECC);
  break;

  case TestSSL:
    ui->comboBoxFunctor->addItem("TestSSL", (long long)&TestSSLHandshake);
    ui->comboBoxFunctor->addItem("TestIOService", (long long)&boost_test::TestIOService);
    ui->comboBoxFunctor->addItem("TestHttpClient", (long long)&boost_test::TestHttpClient);
  break;

  case TestPKI:
    ui->comboBoxFunctor->addItem("TEST PKCS11");
    ui->comboBoxFunctor->addItem("TEST SKF");
  break;
  }
}

void SSLFrame::RunFunctor(TestType type)
{
  int index = ui->comboBoxFunctor->currentIndex();
  switch(type) {
    case TestCrypto:
      if(index == 0)
        TestHash();
      else if(index == 1)
        TestBigNumber();
    break;
  case TestDigest:
    if(index == 0)
      TestSM3();
    else if(index == 1)
      TestSha256();
  break;
  case TestSymmetric:
    if(index == 0)
      TestSM4();
    else if(index == 1)
      TestAES128();
  break;

  case TestAsymmetric:
    if(index == 0)
      TestSM2();
    else if(index == 1)
      TestRSA();
    else if(index == 2)
      TestDSA();
    else if(index == 3)
      TestECC();
  break;

  case TestSSL:
    if(index == 0)
      TestSSLHandshake();
    else if(index == 1)
      boost_test::TestIOService();
    else if(index == 2)
      boost_test::TestHttpClient();
  break;

  case TestPKI:
    if(index == 0)
      TestPKI11("/usr/local/lib/libcastle.so", "as198811");
    else if(index == 1)
      TestSKF("/opt/apps/com.ftsafe.epass3000gm-g/files/lib/libfteps3000gmg.so",
              "as198811");
  break;
  }
}

void SSLFrame::printMsg(const QString& text)
{
    ui->textBrowser->append(text);
}
